<template>
  <div class="_base-count-down no-rtl">
    <div class="content">
      <slot
        v-bind="{
          d: days,
          h: hours,
          m: mins,
          s: seconds,
          hh: `00${hours}`.slice(-2),
          mm: `00${mins}`.slice(-2),
          ss: `00${seconds}`.slice(-2),
        }"
      ></slot>
    </div>
  </div>
</template>

<script>
  export default {
    components: {},
    props: {
      // 传入倒计时时间
      time: {
        type: [Number, String],
        default: 0
      },
      // 传入到期时间
      end: {
        type: [Number, String],
        default: 0
      },
      isMilliSecond: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        days: '0',
        hours: '00',
        mins: '00',
        seconds: '00',
        timer: null,
        curTime: 0
      }
    },
    computed: {
      duration() {
        // 到期时间
        if (this.end) {
          let end = String(this.end).length >= 13 ? +this.end : +this.end * 1000
          end -= Date.now()
          return end
        }
        // 倒数时间
        const time = this.isMiniSecond
          ? Math.round(+this.time / 1000)
          : Math.round(+this.time)
        return time
      }
    },
    watch: {
      // 更新时间的时候，需要同步执行倒计时
      duration() {
        this.countDown()
      }
    },
    mounted() {
      this.curTime = Date.now()
      this.countDown()
    },
    methods: {
      // 开始倒计时
      countDown() {
        this.curTime = Date.now()
        this.updateTime(this.duration)
      },
      // 获得 days，hours,mins，seconds,然后显示到html上，并且通过定时器实时来刷新days，hours,mins，seconds这个几个值
      updateTime(duration) {
        this.timer && clearTimeout(this.timer)
        if (duration < 0) return
        const { dd, hh, mm, ss } = this.durationFormatter(duration)
        this.days = dd || 0
        this.hours = hh || 0
        this.mins = mm || 0
        this.seconds = ss || 0
        // 每个setTimeout产生的任务会直接push到任务队列中；而setInterval在每次把任务push到任务队列前，都要进行一下判断(看上次的任务是否仍在队列中)。
        this.timer = setTimeout(() => {
          // 出于节能的考虑, 部分浏览器在进入后台时(或者失去焦点时), 会将 setTimeout 等定时任务暂停 待用户回到浏览器时, 才会重新激活定时任务。所以需要diffTime
          const now = Date.now()
          const diffTime = Math.floor((now - this.curTime) / 1000)
          this.curTime = now
          this.updateTime(duration - diffTime)
        }, 1000)
      },
      // 辅助函数，将duration转换成天数，小时，分钟，秒数
      durationFormatter(time) {
        if (!time) return { ss: 0 }
        let t = time
        const ss = t % 60
        t = (t - ss) / 60
        if (t < 1) return { ss }
        const mm = t % 60
        t = (t - mm) / 60
        if (t < 1) return { mm, ss }
        const hh = t % 24
        t = (t - hh) / 24
        if (t < 1) return { hh, mm, ss }
        const dd = t
        return { dd, hh, mm, ss }
      }
    }
  }
</script>
<style lang="scss" scoped></style>
